///////////// comments ////////////

#include "combined.h"
#include "commandTable.h"
#include "definitions.h"
#include "stringutil.h"
#include "tEditHandler.h"

// Default constructor...
tEditHandler::tEditHandler() {
	setCharacter( NULL );
	setDest( NULL );
	_nLines = 0;
}

// Additional constructors...
tEditHandler::tEditHandler( Character* character, std::string* dest ) {
	int i = 0;
	char ch = '\0';
	setCharacter( character );
	setDest( dest );
	for ( std::string::iterator it = _dest->begin(); it != _dest->end(); it++ ) {
		ch = *it;
		if ( ch  == '\n' ) {
			i++;
			continue;
		}
		else
			_lines[i] << ch;
	}
	_nLines = i + 1;
}

// Destructor...
tEditHandler::~tEditHandler() {
	setCharacter( NULL );
	setDest( NULL );
}

// Operators...
tEditHandler& tEditHandler::operator = ( tEditHandler& it ) {
	setCharacter( it.getCharacter() );
	setDest( it.getDest() );
	for ( unsigned u=0; u < 40; ++u )
		_lines[u] = it.getLine( u );
	_nLines = it.getNlines();
	return *this;
}

// Protected methods...
void tEditHandler::update() { // protected
	std::string tmp;

	for ( unsigned u=0; u < _nLines; ++u ) {
		tmp << _lines[u];
		if ( u < _nLines - 1 )
			tmp << '\n';
	}

	*_dest = tmp;

	return;
}

// Public accessor methods...
void tEditHandler::setCharacter( Character* character ) {
	_c = character;
	return;
}

Character* tEditHandler::getCharacter() {
	return _c;
}

void tEditHandler::setDest( std::string* dest ) {
	_dest = dest;
	return;
}

std::string* tEditHandler::getDest() {
	return _dest;
}

void tEditHandler::setLine( const unsigned& u, const std::string& line ) {
	_lines[u] = line;
	return;
}

std::string tEditHandler::getLine( const unsigned& u ) {
	return _lines[u];
}

unsigned tEditHandler::getNlines() {
	return _nLines;
}

void tEditHandler::addLine( const std::string& args ) {
	std::string line = trim( args );
	if ( line.empty() ) {
		_nLines++;
	} else {
		// Append new text to the end of the last line.
		if ( _nLines < 1 ) {
			_nLines = 1;
			_lines[0] = line;
		} else {
			std::string old_line = trim( _lines[_nLines-1] );
			std::string tmp = trim( line );
			std::string new_line = trim( old_line + ' ' + tmp );

			// Start a new line every 70 characters.
			_lines[_nLines-1].erase();
			int i = 1;
			for ( std::string::iterator it = new_line.begin(); it != new_line.end(); it++, i++ ) {
				_lines[_nLines-1] << (*it);
				if ( i == 69 ) {
					i = 0;
					_nLines++;
				}
			}
		}
	}

	update();

	return;
}

void tEditHandler::insertLine( const std::string& args ) {
	std::string input = trim( args );
	if ( !input.empty() ) {
		std::string line_num;
		std::string line;
		split( input, line_num, line );
		int num = atoi( line_num.c_str() ) - 2;
		if ( num < 1 )
			return;
		int loops = _nLines - num + 1;
		_nLines++;
		for ( int i=0; i < loops; i++ )
			_lines[_nLines-i] = _lines[_nLines-i-1];
		_lines[num+1] = line;
	}

	update();

	return;
}

void tEditHandler::removeLine( const std::string& args ) {
	std::string line = trim( args );
	if ( line.empty() ) {
		if ( _nLines < 1 ) { // Can't erase lines if there are none left to erase!
			update();
			return;
		}
		_lines[--_nLines].erase();
	} else {
		unsigned num = atoi( line.c_str() ) - 1;
		if ( num < 1 )
			return;
		if ( num < 1 || num > _nLines ) {
			update();
			return;
		}
		int loops = _nLines - num;

		_lines[num].erase();

		for ( int i=0; i < loops; i++ )
			_lines[num+i] = _lines[num+i+1];

		_lines[_nLines-1].erase();
		_nLines--;
	}

	update();

	return;
}

void tEditHandler::replaceLine( const std::string& args ) {
	std::string line_num;
	std::string line;
	split( args, line_num, line );
	unsigned num = atoi( line_num.c_str() );

	if ( num < 1 )
		return;

	if ( line.size() <= 70 && num <= _nLines )
		_lines[ num - 1 ] = line;

	update();

	return;
}

std::string tEditHandler::editWindow() {
	std::string buf;

	buf << "  ----------------------------------------------------------------------------\n\r";
	buf << " |                             {CSymphony Text Editor{x                           |\n\r";
	buf << " | Type 'help' for a list of commands, or 'help <command>' for specific info  |\n\r";
	buf << " |----------------------------------------------------------------------------|\n\r";
	for ( unsigned u=0; u < _nLines; ++u ) {
		buf << " | ";
		if ( u <= 8 )
			buf << " ";
		buf << u+1 << ": " << format( 70, _lines[u] ) << " |\n\r";
	}
	buf << "  ----------------------------------------------------------------------------\n\r";

	return buf;
}

////////////////////////////////////////////// tEditHandler //////////////////////////////////////////////

tEditHandler* tEditList::getHandler( const std::string& name ) {
	for ( std::list< tEditHandler* >::iterator it = getList().begin(); it != getList().end(); ++it )
		if ( (*it)->getCharacter()->getName() == name )
			return *it;
	return NULL;
}

std::list< tEditHandler* >& tEditList::getList() {
	return _vList;
}

void tEditList::add( tEditHandler* handler ) {
	getList().push_back( handler );
	return;
}

void tEditList::act( Character* character, const std::string& args ) {
	tEditHandler* vh = NULL;

	if ( ( vh = Instance().getHandler( character->getName() ) ) == NULL ) {
		if ( character->getStatus() == CONNECTED )
			add( new tEditHandler( character, character->getFullDescP() ) );
		else if ( character->getStatus() == NEDIT )
			add( new tEditHandler( character, character->getNote()->getBodyP() ) );
		else if ( character->getStatus() == REDIT )
			add( new tEditHandler( character, character->getRoom()->getDescP() ) );
		else if ( character->getStatus() == OEDIT )
			add( new tEditHandler( character, character->getObject()->getFullDescP() ) );
		else if ( character->getStatus() == MEDIT )
			add( new tEditHandler( character, character->getMob()->getFullDescP() ) );
		else {
			character->Send( "{RERROR{x\n\r" );
			return;
		}
		character->Send( "Welcome to Symphony Text Editor!\n\r" );
		return;
	}

	if ( tCommandTable::Instance().execute( character, args ) == 0 )
		character->Send( vh->editWindow() );

	return;
}
